package cn.tsinghua.comsmacitccntsinghua.WS;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tencent.tinker.lib.tinker.TinkerInstaller;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;


import cn.tsinghua.comsmacitccntsinghua.DeviceInfo;
import cn.tsinghua.comsmacitccntsinghua.VO.status.Status;
import cn.tsinghua.comsmacitccntsinghua.WS.WebSocketCallback;
import cn.tsinghua.comsmacitccntsinghua.entity.Res;
import cn.tsinghua.comsmacitccntsinghua.estar.HttpImpl;
import cn.tsinghua.comsmacitccntsinghua.tinker.SampleApplicationLike;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

/**
 * @Author yjl
 * @create 2021/10/13 14:45
 */
public class EInfoWebSocketService extends Service {

    private static final String TAG = "websocket";
    private static final String WEBSOCKET_HOST_PORT = "ws://192.168.2.120:8181/websocket/" + SampleApplicationLike.getStrData("boardId");
    private boolean connected = false;
    private int hearbeatTime = 25*1000;
    private int reconnectTimes = 0 ;//重连次数
    private int heartBeatlostTimes = 3;
    private int mCurrentStatus = WsStatus.DISCONNECTED;
    OkHttpClient mClient;
    Request request;
    WebSocket mWebSocket;
    Boolean isManulClose = false; //是否为手动关闭连接
    private boolean isNeedReconnect = true;
    private final static int RECONNECT_INTERVAL = 10 * 1000;    //重连自增步长

    private Runnable reconnectRunnable = new Runnable() {
        @Override
        public void run() {
            Log.e("websocket","服务器重连中....");
            connect();
        }
    };

    private Handler WsMainHandler = new Handler(Looper.getMainLooper());

    private int reconnectTimeout = 5000; //重连时间



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new LocalBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"onstartCommand");
        return START_STICKY;

    }

    @Override
    public void onCreate() {
        Log.d(TAG,"oncreate");
        super.onCreate();
        mWebSocket = connect();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(mWebSocket != null){
            close();
        }
    }

    /**********************************************************************方法区************************************************************/

    //连接websocket
    private synchronized WebSocket connect(){
        //检查网络连接
        if(!isNetworkConnected()){
            setmCurrentStatus(WsStatus.DISCONNECTED);
            return null;
        }
        switch (getmCurrentStatus()){
            case WsStatus.CONNECTED:
            case WsStatus.CONNECTING:
                break;
            default:
                setmCurrentStatus(WsStatus.CONNECTING);
        }
        mWebSocket = initWebsocket();
        return mWebSocket;
    }

    //开始连接websocket
    private WebSocket initWebsocket(){
        Log.d(TAG,"connecting.." + WEBSOCKET_HOST_PORT);
        if(mClient == null){
            mClient = new OkHttpClient.Builder()
                    .build();
        }
        if(request == null){
            //配置Socket
            request = new Request.Builder().get().url(WEBSOCKET_HOST_PORT).build();
        }
        mWebSocket = mClient.newWebSocket(request,new WebSocketHandler());
        return mWebSocket;
    }

    //检测网络是否连接
    private boolean isNetworkConnected(){
        Context context = getApplicationContext();
        if(context !=null){
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if(mNetworkInfo !=null){
                return  mNetworkInfo.isAvailable();
            }
        }
        return false;
    }
    //设置当前网络连接状态

    public void send(Res res){
        Log.d(TAG,"send " + res.getData());
        if(mWebSocket !=null){
            mWebSocket.send(JSON.toJSONString(res));
        }
    }

    public void close(){
        if(mWebSocket != null){
            boolean shutDownFlag = mWebSocket.close(1000,"manul close");
            Log.d(TAG,"shutDownFlag" + shutDownFlag);
            mWebSocket = null;
        }
    }

    /**
     * 拿到websocket
     * @return
     */
    public WebSocket getmWebSocket(){
        return mWebSocket;
    }

    /**
     * 检测Websocket是否连接
     * @return
     */
    public synchronized boolean isWsConnected(){
        return mCurrentStatus == WsStatus.CONNECTED;
    }

    /**
     * 停止websocket连接
     */
    public void stopConnecet(){
        isManulClose = true;
        disconnect();
    }
    /**
     * 取消重连
     */
    private void cancelReconnect(){
        WsMainHandler.removeCallbacks(reconnectRunnable);
    }


    /**
     * 断开连接
     */
    private void disconnect(){
        if(mCurrentStatus == WsStatus.DISCONNECTED){
            return;
        }
        cancelReconnect();
        if(mClient != null){
            mClient.dispatcher().cancelAll();
        }
        if(mClient != null){
            boolean isClosed = mWebSocket.close(WsStatus.CODE.NORMAL_CLOSE,WsStatus.TIP.NORMAL_CLOSE);
            if(!isClosed){
                Log.e("websocket","服务器连接失败");
            }
        }
        setmCurrentStatus(WsStatus.DISCONNECTED);
    }

    /**
     * 发送消息
     * @return
     */
    private boolean send(Object msg){
        boolean isSend = false;
        if(mWebSocket != null && mCurrentStatus == WsStatus.CONNECTED){
            if(msg instanceof String){
                isSend = mWebSocket.send((String)msg);
            }else if(msg instanceof ByteString){
                isSend = mWebSocket.send((ByteString)msg);
            }
            if(!isSend){

            }
        }
        return isSend;
    }

    /**
     * 重连
     */
    private void tryReconnect(){
        if(isManulClose){
            return;
        }
        Log.e("websocket","重连次数" + reconnectTimes);
        if(!isNetworkConnected()){
            setmCurrentStatus(WsStatus.DISCONNECTED);
            Log.d("websocket","网络未连接");
            return;
        }
//        connect();
        setmCurrentStatus(WsStatus.RECONNECT);
        long delay = reconnectTimes * RECONNECT_INTERVAL;
        WsMainHandler.postDelayed(reconnectRunnable,delay);//运行重连
        reconnectTimes++;
        //重连五次 取消重连
        if(reconnectTimes > 5){
            cancelReconnect();
        }
    }

    /**
     * 已连接标识符，停止连接
     */
    private void connected(){
        cancelReconnect();
    }


    public synchronized int getmCurrentStatus() {
        return mCurrentStatus;
    }

    public synchronized void setmCurrentStatus(int mCurrentStatus) {
        this.mCurrentStatus = mCurrentStatus;
    }

    /**********************************************************************************************静态类区***************************************************************/

    Timer timer;
    TimerTask timerTask;
    private class WebSocketHandler extends WebSocketListener{
        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            Log.d(TAG,"onOpen");
            setmCurrentStatus(WsStatus.CONNECTED);
            connected();
            //发心跳包
            connected = true;
            //连接成功后给系统每25秒发送一个心跳包
            timer = new Timer();
            timerTask = new TimerTask() {
                @Override
                public void run() {
                    send(new Res("20000","ping"));
                    Log.e("websocket","剩余检测心跳包次数" + String.valueOf(heartBeatlostTimes));
                    heartBeatlostTimes--; //每25s +1
                    if(heartBeatlostTimes < 0){
                        tryReconnect();
                        timer.cancel();
                    }
                }
            };
            timer.schedule(timerTask,0,hearbeatTime);
        }

        @Override
        public void onMessage(WebSocket webSocket, String text) {
            Log.d(TAG,"onMessage" + text);//接到 update
            solveWSMessage(text);
        }

        @Override
        public void onClosed(WebSocket webSocket, int code, String reason) {
            Log.d(TAG,"onClosed");
            connected = false;
        }
        @Override
        public void onFailure(WebSocket webSocket, Throwable t, @Nullable Response response) {
            Log.d(TAG,"onFailure " + t.getMessage());
            tryReconnect();
            Log.e("websocket","尝试重新连接");
            connected = false;
        }
    }

    public void solveWSMessage(String msg){
        Res res = JSONObject.parseObject(msg,Res.class);
        String code = res.getData();
        String data = res.getData();
        if(!(code.equals("20000"))) return;
        switch (data){
            case "hoxfix":
                HttpImpl.getHotFix(getApplicationContext());
                break;
            case "coldfix":
                //TODO 预留
                break;
        }

        switch (res.getData()){
            case "pong" :
                synchronized (this){
                    heartBeatlostTimes = 3 ; //接到心跳包置为3次 否则每25s 扣掉1
                }
                break;
        }
    }

    public void methodInService(){
        Log.d("WSService","调用Service内的方法");
    }

    public class LocalBinder extends Binder{
        EInfoWebSocketService getService(){
            return EInfoWebSocketService.this;
        }
        public void callMethodInService(){
            methodInService();
        }
    }

}
